package net.projectRPG.src;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;

import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;

import com.jme3.niftygui.NiftyJmeDisplay;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;

import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;

import com.jme3.scene.Spatial;
import com.jme3.renderer.Camera;
import com.jme3.scene.Node;

import java.util.ArrayList;
import java.util.List;

import com.jme3.util.SkyFactory;

import com.jme3.light.DirectionalLight;
import com.jme3.post.FilterPostProcessor;
import com.jme3.math.ColorRGBA;
import com.jme3.water.WaterFilter;
import java.util.HashSet;
import java.util.Set;
import com.jme3.terrain.geomipmap.TerrainLodControl;

import com.jme3.post.filters.BloomFilter;
import com.jme3.post.filters.CartoonEdgeFilter;
import com.jme3.post.filters.DepthOfFieldFilter;
import com.jme3.post.filters.LightScatteringFilter;
import com.jme3.post.filters.CartoonEdgeFilter;

import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.texture.Texture2D;

import com.jme3.audio.AudioNode;

import com.jme3.export.Savable;

import com.jme3.export.binary.BinaryImporter;
import com.jme3.export.binary.BinaryExporter;
import java.io.Serializable;
import java.io.IOException;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.InputCapsule;
import com.jme3.export.OutputCapsule;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.audio.AudioNode;
import com.jme3.shadow.BasicShadowRenderer;


public class Area implements Serializable, Savable  {

    public float waterLevel;
    public AudioNode globalSound;
    
    public enum AreaName {
      beach, cave
    }
    
    public Area(Main main, AreaName areaName) {
        // grab some variables from the main application for later use
        Node rootNode = main.getRootNode();
        Camera camera = main.getCamera();
        BulletAppState bulletAppState = main.bulletAppState;
        Player player = main.player;

        String skyBoxPath = "";
        String terrainPath = "";
        
        switch(areaName) {
            case beach:
                skyBoxPath = "Textures/SkyboxIsland.dds";
                terrainPath = "Scenes/Beach.j3o";
                break;
            case cave:
                skyBoxPath = "";
                terrainPath = "Scenes/Cave.j3o";
                break;                
        }
        
        // create sky
        if(skyBoxPath != "")
        {
            rootNode.attachChild(SkyFactory.createSky(
                    main.getAssetManager()
                , "Textures/SkyboxIsland.dds", false));      
        }
        
        // create ground
        Spatial terrain = main.getAssetManager().loadModel(terrainPath);    
        Node terrainAsNode = (Node) terrain;
        Node terrainOnlyNode = (Node) terrainAsNode.getChild("Terrain"); 
        Spatial terrainSpatial = (Spatial) terrainOnlyNode;
        rootNode.attachChild(terrainSpatial);   

        CollisionShape sceneShape =
                CollisionShapeFactory.createMeshShape((Node) terrainSpatial);
        RigidBodyControl landscape = new RigidBodyControl(sceneShape, 0);
        terrainSpatial.addControl(landscape);   
        terrainSpatial.setShadowMode(ShadowMode.Receive);        
        
        // add LOD for terrain
        TerrainLodControl lodControl = ((Node)terrainSpatial).getControl(TerrainLodControl.class);
            if (lodControl != null)
                lodControl.setCamera(camera);

        rootNode.attachChild(terrain);   
        bulletAppState.getPhysicsSpace().add(landscape);               
        
        DirectionalLight sun = new DirectionalLight();
        Vector3f lightDir = null;
        
        switch(areaName) {
            case beach:
                // add light, needed for water
                lightDir = new Vector3f(-0.37352666f, -0.50444174f, -0.7784704f);
                sun.setDirection(lightDir);
                sun.setColor(ColorRGBA.White.clone().multLocal(1));

                // add water
                final WaterFilter water = new WaterFilter(rootNode, lightDir);
                water.setWaveScale(0.003f);
                water.setMaxAmplitude(1f);
                water.setFoamExistence(new Vector3f(.2f, 1, 0.1f));
                water.setFoamTexture((Texture2D) main.getAssetManager().loadTexture("Common/MatDefs/Water/Textures/foam2.jpg"));
                water.setRefractionStrength(0.2f);
                waterLevel = -0.5f;
                water.setWaterHeight(waterLevel);        
                main.areaProcessor.addFilter(water);

                // bloom & depth of field (blur)
                BloomFilter bloomBeach =new BloomFilter();
                bloomBeach.setExposurePower(55);
                bloomBeach.setBloomIntensity(1.0f);
                main.areaProcessor.addFilter(bloomBeach);
                LightScatteringFilter lsfBeach = new LightScatteringFilter(lightDir.mult(-300));
                lsfBeach.setLightDensity(1.0f);
                main.areaProcessor.addFilter(lsfBeach);
                DepthOfFieldFilter dofBeach =new DepthOfFieldFilter();
                dofBeach.setFocusDistance(0);
                dofBeach.setFocusRange(100);    
                main.areaProcessor.addFilter(dofBeach);       
                break;
            case cave:
                rootNode.setShadowMode(ShadowMode.Off);
                BasicShadowRenderer bsr = new BasicShadowRenderer(main.getAssetManager(), 256);
                bsr.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
                main.getViewPort().addProcessor(bsr);
                break;                
        }        
        

        main.getViewPort().addProcessor(main.areaProcessor);

        // add sun if exists for area
        if(lightDir != null)
            rootNode.addLight(sun);
        
        // find starting point
        Node terrainNode = (Node) terrain;
        Node ghostNode = (Node) terrainNode.getChild("Ghost");
        Spatial wpStart =  terrainNode.getChild("wpStart");
        // move player to specific location
        //player.setPhysicsLocation(wpStart.getWorldTranslation());
        
        Vector3f playerStart = wpStart.getWorldTranslation();
        wpStart.removeFromParent();        
        player.setPhysicsLocation(playerStart);

        
    }
    
    @Override
    public void write(JmeExporter ex) throws IOException {
        OutputCapsule oc = ex.getCapsule(this);
        oc.write(waterLevel, "waterLevel", 0f);

    }

    public void read(JmeImporter im) throws IOException {
        InputCapsule ic = im.getCapsule(this);
        waterLevel = ic.readFloat("waterLevel", 0f);
    }
}
